package org.ajc.auth.service.impl;

import org.ajc.auth.domain.Permission;
import org.ajc.auth.service.IPermissionScanService;
import org.ajc.auth.service.IPermissionService;
import org.ajc.base.annotation.AjcPermission;
import org.ajc.base.enums.RequestTypeEnum;
import org.ajc.base.util.ClassUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

@Service
@Transactional
public class PermissionScanServiceImpl implements IPermissionScanService {

    @Value("${scan.package-name}")
    private String packages;

    @Autowired
    private IPermissionService permissionService;

    @Override
    public void scan() throws ClassNotFoundException {

        // 清空表中的数据
        permissionService.deleteAll();

        // 获取所有的Controller
        //使用传入包名
        List<Class> allClassName = ClassUtils.getAllClassName(packages);
        //拿到包下的所有文件  循环问一个文件含有自定义注解的类
        for (Class clazz : allClassName ) {
            // 拿到含有注解 (此处该进行强制转换)
            AjcPermission annotation = (AjcPermission)clazz.getAnnotation(AjcPermission.class);
            // 判断是否有权限注解
            if (Objects.isNull(annotation)){
                continue ; //如果为空就跳转下次循环
            }
            // 获取所有的方法 拿到方法上有RequestMapping注解 (此处该进行强制转换)
            RequestMapping annotation2 = (RequestMapping)clazz.getAnnotation(RequestMapping.class);
            // 获取的URL的路径 第一个
            String classURL = annotation2.value()[0];
            // 获取parent 对象
            Permission parent = new Permission();
            // 设置属性
            parent.setName(annotation.name());
            parent.setDescs(annotation.desc());
            parent.setParent(null);
            parent.setSn(clazz.getSimpleName());
            // 类上的URL
            parent.setUrl(classURL);
            // 将拿到的parent对象封装
            permissionService.insert(parent);
            // 获取的所有方法
            Method[] methods = clazz.getMethods();
            // 循环所有方法
            for (Method m: methods) {
                // 判断方法是否有权限注解
                AjcPermission annotation1 = m.getAnnotation(AjcPermission.class);
                if (Objects.isNull(annotation1)){
                    continue; //如果为空就跳转下次循环
                }
                //获取Permission 对象
                Permission permission = new Permission();
                //设置属性
                permission.setName(annotation1.name());
                permission.setDescs(annotation1.desc());
                permission.setParent(parent);
                // sn 唯一标识： 就是 Controller + 方法
                // 拿到循环包下的文件 " : " 方法名
                permission.setSn(clazz.getSimpleName()+":"+m.getName());
//              permission.setUrl();
                // 方法上的 URL (使用枚举来获取方法上的url)
                String methodUrl = getMethodUrl(m);
                permission.setUrl(classURL+methodUrl);

                // 入库
                permissionService.insert(permission);
            }
        }
    }
    public String getMethodUrl(Method method){
        String methodUrl = "";
        // 取枚举中定义的所有的请求类型
        RequestTypeEnum[] requestTypeEnums = RequestTypeEnum.values();
        for (RequestTypeEnum typeEnum : requestTypeEnums) {
            // 根据枚举中的不同的请求类型的class获取该类型对应的注解对象
            Annotation annotation = method.getAnnotation(typeEnum.getRequestType());
            // 如果该请求类型注解不存在就跳过
            if(Objects.isNull(annotation)){
                continue;
            }
            try {
                // 如果该请求类型注解存在,就获取它里面的value方法
                Class<? extends Annotation> aClass = annotation.annotationType();
                // aClass 是 对应的 请求类型的  字节码对象
                Method annotationMethod = aClass.getMethod("value");
                // 通过invoke调用该对象的value方法,获取结果
                // 反射执行 方法 方法名.invoke(对象)

                String[] value = (String[]) annotationMethod.invoke(annotation);
                // 如果value不为空且长度大于0,就赋值给methodUrl,并跳出循环
                if(value != null && value.length > 0){
                    methodUrl = value[0];
                    break;
                }
            }catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
        return methodUrl;

    }
}
